package com.killer.auth.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.killer.search.entity.SkuInfo;
import com.killer.auth.service.ISearchService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SearchServiceImpl implements ISearchService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    private final static int PAGE_SIZE = 20;

    @Override
    public Map<String, Object> search(Map<String, String> params) throws Exception {
        if (params == null) {
            return null;
        }
        Map<String, Object> result = new HashMap<>();
        String pageNumValue = params.get("pageNum") != null ? params.get("pageNum") : "1";
        int pageNum = Integer.valueOf(pageNumValue);
        SearchRequest searchRequest = new SearchRequest("goods");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.from(pageNum <= 0 ? 0 : (pageNum - 1) * PAGE_SIZE);
        searchSourceBuilder.size(PAGE_SIZE);
        //组合条件对象
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //关键词
        if (StringUtils.isNotBlank(params.get("keywords"))) {
            //must,必须满足,并且参与打分
            boolQueryBuilder.must(QueryBuilders.matchQuery("name", params.get("keywords")).operator(Operator.AND));
        }
        //品牌
        if (StringUtils.isNotBlank(params.get("brand"))) {

            boolQueryBuilder.filter(QueryBuilders.termsQuery("brandName", params.get("brand")));
        }
        //规格 {'颜色': '红色', '尺寸': '20英寸'}
        for (String key : params.keySet()) {
            if (key.startsWith("spec_")) {
                //"spec_机身内存":8G
                //%2B是+号的意思，通过 GET方式传值的时候，+号会被浏览器处理为空，所以需要转换为%2b
                String value = params.get(key).replaceAll("%2B", "+");
                boolQueryBuilder.filter(QueryBuilders.termsQuery("specMap." + key.substring(5) + ".keyword", value));
            }
        }
        //价格
        if (StringUtils.isNotBlank(params.get("price"))) {
            String[] p = params.get("price").split("-");
            //大于最低价格
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(p[0]));
            //如果 是 0-500  500-1000这种，非3000以上这种
            if (p.length == 2) {
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(p[1]));
            }
        }
        searchSourceBuilder.query(boolQueryBuilder);
        //高亮
        HighlightBuilder.Field field = new HighlightBuilder.Field("name").preTags("<span style='color:red'>").postTags("</span>");
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field(field);
        searchSourceBuilder.highlighter(highlightBuilder);
        //品牌聚合(分组)查询
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("skuBrand").field("brandName");
        searchSourceBuilder.aggregation(termsAggregationBuilder);
        //规格聚合(分组)查询
        searchSourceBuilder.aggregation(AggregationBuilders.terms("skuSpec").field("spec"));
        //排序
        if (StringUtils.isNotBlank(params.get("sortField"))) {
            if (StringUtils.equalsIgnoreCase("asc", params.get("sortRule"))) {
                searchSourceBuilder.sort(SortBuilders.fieldSort(params.get("sortRule")).order(SortOrder.ASC));
            } else {
                searchSourceBuilder.sort(SortBuilders.fieldSort(params.get("sortRule")).order(SortOrder.DESC));
            }
        }
        //向搜索请求对象中设置搜索源
        searchRequest.source(searchSourceBuilder);
        //执行查询，返回结果对象
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits searchHits = searchResponse.getHits();
        List<SkuInfo> skuInfoList = new ArrayList<>();
        for (SearchHit searchHit : searchHits) {
            SkuInfo skuInfo = JSONObject.parseObject(searchHit.getSourceAsString(), SkuInfo.class);
            Map<String, HighlightField> highlightFieldsMap = searchHit.getHighlightFields();
            if (highlightFieldsMap != null && highlightFieldsMap.size() > 0) {
                skuInfo.setName(highlightFieldsMap.get("name").getFragments()[0].toString());
            }
            skuInfoList.add(skuInfo);
        }
        result.put("data", skuInfoList);
        //总条数
        long total = searchHits.getTotalHits().value;
        result.put("total", total);
        //总页数
        long totalPage = total % PAGE_SIZE == 0 ? total / PAGE_SIZE : total / PAGE_SIZE + 1;
        result.put("totalPages", totalPage);
        //获取品牌聚合结果
        Aggregations aggregations = searchResponse.getAggregations();
        Map<String, Aggregation> aggMap = aggregations.asMap();

        ParsedStringTerms brandTerms = (ParsedStringTerms) aggMap.get("skuBrand");
//        "skuBrand" : {
//                "buckets" : [
//                    {
//                        "key" : "奇",
//                            "doc_count" : 480
//                    }
//                ]
//         }
        List<String> brandList = brandTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
        result.put("brandList", brandList);
        //获取规格聚合结果
        ParsedStringTerms specTerms = (ParsedStringTerms) aggMap.get("skuSpec");
        List<String> specList = specTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
        Map<String, Set<String>> specMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(specList)) {
            for (String spec : specList) {
                Map<String, String> map = JSONObject.parseObject(spec, Map.class);
                for (Map.Entry<String, String> entry : map.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    Set<String> specValues = specMap.get(key);
                    if (specValues == null) {
                        specValues = new HashSet<>();
                    }
                    specValues.add(value);
                    specMap.put(key, specValues);
                }
            }
        }
        result.put("skuSpec", specMap);
        //返回当前页
        result.put("pageNum", pageNum);
        return result;

    }
}
